//============================================================================
// Name        : IndexBuilder.cpp
// Author      : lucmir@dcc.ufmg.br
// Description :
//============================================================================

#include "IndexBuilder.h"

IndexBuilder::IndexBuilder(std::string tmpDir)
	: tmpDir(tmpDir),
	  runsCount(0) {
	this->run = new Run();
	this->lexon = new Lexon();
	this->index = new Index(this->lexon);
	this->docIdx = new DocumentIndex();
}

IndexBuilder::IndexBuilder()
	: runsCount(0) {
	this->tmpDir = ".";
	this->run = new Run();
	this->lexon = new Lexon();
	this->index = new Index(this->lexon);
	this->docIdx = new DocumentIndex();
}

IndexBuilder::~IndexBuilder() {
	this->run->clear();
	delete this->run;
	this->index->closeToWrite();
}

void IndexBuilder::manageRuns(Lexon *lexon) {
	// Check if the max number of registries in memory was reached
	if(this->run->getLen() >= MAX_RUN_SIZE) {
		this->writeRunToFile(lexon);
	}

}

void IndexBuilder::writeRunToFile(Lexon *lexon) {
	if(this->run->getLen() > 0) {
		// Write to file
		std::ostringstream tmpFileName;
		tmpFileName << this->tmpDir << "/run" << ++this->runsCount << ".tmp";
		this->run->printToFile(tmpFileName.str(), lexon);
	}
}

bool IndexBuilder::buildIndex() {
	std::ifstream files[this->runsCount];
	IndexRegistry idxRegistry;
	idxRegistry.registry = Registry(0, 0, 0);
	bool readResult;
	std::priority_queue<IndexRegistry> heap;

	if(!this->index->isOpenToWrite()) {
		std::cout << "\nERRO: Não foi possível construir o índice.\n";
		return false;
	}

	// Open runs files
	for(unsigned int i=0; i<this->runsCount; i++) {
		std::ostringstream tmpFileName;

		tmpFileName << this->tmpDir << "/run" << i+1 << ".tmp";
		files[i].open(tmpFileName.str().c_str());
		if(!files[i].is_open()) {
			std::cout << "\nERRO: Não foi possível abrir o arquivo: " << tmpFileName << "\n";
			return false;
		}

		// Read the ﬁrst registry from each run
		readResult = this->run->readFromFile(files[i], idxRegistry.registry);
		if(readResult) {
			idxRegistry.runId = i;
			heap.push(idxRegistry);
		}
	}

	// While the heap is noempty
	do {
		// Remove the root of the heap.
		idxRegistry = heap.top();
		heap.pop();

		// Write registry to index
		this->index->insert(idxRegistry.registry);

		// Update documents information
		this->docIdx->updateDocInfo(idxRegistry.registry.getDocId(),
				idxRegistry.registry.getFreq(), this->docIdx->getNumDocs(),
				this->lexon->getTermTf(idxRegistry.registry.getTermId()) );

		// Try to read the next candidate registry from the same run
		readResult = this->run->readFromFile(files[idxRegistry.runId], idxRegistry.registry);
		if(readResult) {
			heap.push(idxRegistry);
		}
	} while(!heap.empty());

	// Close and delete files
	for(unsigned int i=0; i<this->runsCount; i++) {
		files[i].close();
		std::ostringstream tmpFileName;
		tmpFileName << this->tmpDir << "/run" << i+1 << ".tmp";
		remove(tmpFileName.str().c_str());
	}
	return true;
}

Lexon *IndexBuilder::getLexon() {
	return this->lexon;
}

DocumentIndex *IndexBuilder::getDocIdx() {
	return this->docIdx;
}

Index *IndexBuilder::getIndex() {
	return this->index;
}

Run *IndexBuilder::getRun() {
	return this->run;
}
